package com.rupertjones.globalcron.domain.scheduling;

import com.rupertjones.globalcron.domain.JobDescriptor;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.springframework.scheduling.quartz.QuartzJobBean;

import static java.lang.String.format;

public class QuartzJob extends QuartzJobBean implements StatefulJob {
    private JobExecutionContext context;
    private JobDescriptor jobDescriptor;
    private static final Logger LOG = Logger.getLogger(QuartzJob.class);
    private JobExecutionListener listener;

    public void setJobDescriptor(JobDescriptor jobDescriptor) {
        this.jobDescriptor = jobDescriptor;
    }

    public void setJobExecutionListener(JobExecutionListener listener) {
        this.listener = listener;
    }

    public JobDescriptor getJobDescriptor() {
        return jobDescriptor;
    }

    public String getSummary() {
        return format("[id: %s] [name: %s] [cron: %s @ %s] [enabled: %s] host: [%s]",
                jobDescriptor.getId(), jobDescriptor.getName(), jobDescriptor.getCron(),
                jobDescriptor.getTimezone(), jobDescriptor.isEnabled(), jobDescriptor.getHost().getSummary());
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        long start = 0;
        long end = 0;
        boolean executed = false;

        Executable runnable = jobDescriptor.getRunnable();
        StringBuilder messageHolder = new StringBuilder();

        if (jobDescriptor.canRun())  {
            LOG.info("Executing: " + getSummary());
            start = System.currentTimeMillis();
            runnable.run();
            end = System.currentTimeMillis();
            String message = format("Completed Executing: %s in %s ms, Next Fire Time: %s",
                    getSummary(), (start - end), context.getNextFireTime());
            messageHolder.append(message);
            LOG.info(message);
            executed = true;
        } else {
            executed = false;
            String message = format("Job triggered, but script not executing [%s]", getSummary());
            messageHolder.append(message);
            LOG.info(message);
        }

        ExecutionContext executionContext = new ExecutionContext();
        executionContext.setJobDescriptor(jobDescriptor);
        executionContext.setTimeTaken((end - start));
        executionContext.setExecutedNormally(executed && runnable.executedNormally());
        executionContext.setOutput(runnable.getOutput());
        executionContext.setSummary(messageHolder.toString());
        executionContext.setNextFire(context.getNextFireTime());
        executionContext.setLastFire(context.getFireTime());
        afterExecution(executionContext);
    }

    private void afterExecution(ExecutionContext executionContext) {
        if (listener != null) {
            listener.afterExecution(executionContext);
        }
    }
}
